package com.zcn.io.web.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zcn.io.common.exception.ServerException;
import com.zcn.io.common.exception.ServiceException;
import com.zcn.io.web.api.entity.OrderPayAgentDetailVo;
import com.zcn.io.web.api.query.AnswerStatisticQuery;
import com.zcn.io.common.query.PayDetailStatisticsQuery;
import com.zcn.io.common.util.PayCalculateUtils;
import com.zcn.io.common.vo.OrderMainForTrusteeshipVo;
import com.zcn.io.common.vo.statisticsVo.OrderAgentPayDetailVo;
import com.zcn.io.common.vo.statisticsVo.OrderPayDetailStatisticsMainVo;
import com.zcn.io.common.vo.statisticsVo.OrderPayDetailVo;
import com.zcn.io.web.api.entity.StudioExpenses;
import com.zcn.io.web.mapper.StatisticsMapper;
import com.zcn.io.web.utils.SingleThreadExecutor;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @desc:
 * @author: 202438 邱建伟
 * @date: 2024/9/28 17:29
 * @Copyright (c) 2024, 2024 Inc. All rights reserved.
 */
@Service
@RequiredArgsConstructor
public class StatisticsService {

    private final StatisticsMapper statisticsMapper;
    private final StudioExpensesService studioExpensesService;

    public OrderPayDetailStatisticsMainVo payDetailStatisticsAll(PayDetailStatisticsQuery query) {
        //查询出所有的交易明细并关联对应的订单信息
        List<OrderPayDetailVo> orderPayDetailInfos = statisticsMapper.listOrderPayDetailByQuery(query);
        //按照中介进行分组,计算每个分组统计明细
        Map<String, List<OrderPayDetailVo>> agentMap = orderPayDetailInfos.stream().collect(Collectors.groupingBy(OrderPayDetailVo::getIndexId));
        //获取当前时间段的工作室支出信息
        List<StudioExpenses> studioExpenses = studioExpensesService.listAllByQuery(query);
        OrderPayDetailStatisticsMainVo result = new OrderPayDetailStatisticsMainVo();
        result.setOrderAgentPayDetailVos(new ArrayList<>());
        result.setTotalStudioExpenditure(studioExpensesTotal(studioExpenses));
        for (String key : agentMap.keySet()) {
            List<OrderPayDetailVo> agencyNameDetailList = agentMap.get(key);
            OrderAgentPayDetailVo orderAgentPayDetailVo = new OrderAgentPayDetailVo();
            //中介名称
            orderAgentPayDetailVo.setAgentName(key);
            //总收入
            orderAgentPayDetailVo.setTotalIncome(getAgentTotal(agencyNameDetailList, OrderPayDetailVo::getPayValue));
            //总支出
            orderAgentPayDetailVo.setTotalExpense(getAgentTotal(agencyNameDetailList, OrderPayDetailVo::getRebateValue));
            //总利润
            orderAgentPayDetailVo.setProfit(PayCalculateUtils.sub(orderAgentPayDetailVo.getTotalIncome(), orderAgentPayDetailVo.getTotalExpense()));
            //各种收款方式的收入map
            orderAgentPayDetailVo.setIncomeWayMap(getTotalMap(agencyNameDetailList, OrderPayDetailVo::getPayWay, OrderPayDetailVo::getPayValue));
            //各种支出方式的支出map
            orderAgentPayDetailVo.setExpenditureWayMap(getTotalMap(agencyNameDetailList, OrderPayDetailVo::getRebateWay, OrderPayDetailVo::getRebateValue));
            //各种业务的总收款map
            orderAgentPayDetailVo.setBusinessIncomeMap(getTotalMap(agencyNameDetailList, OrderPayDetailVo::getBusinessType, OrderPayDetailVo::getPayValue));
            //各种业务总利润Map
            orderAgentPayDetailVo.setBusinessProfitMap(getBusinessProfitMap(agencyNameDetailList));
            //各种交易类型的map(新接/续费)
            orderAgentPayDetailVo.setTransactionTypeMap(getTgTransactionTypeMap(agencyNameDetailList));
            result.getOrderAgentPayDetailVos().add(orderAgentPayDetailVo);
        }
        totalMapHandle(result, orderPayDetailInfos, studioExpenses);
        List<OrderAgentPayDetailVo> sortedList = result.getOrderAgentPayDetailVos().stream()
                .sorted(Comparator.comparing(
                        vo -> {
                            // 尝试将amount字符串转换为Double
                            try {
                                return Double.parseDouble(vo.getAgentName());
                            } catch (NumberFormatException e) {
                                // 转换失败的处理，例如返回Double.NaN表示无效值，或抛出异常
                                // 这里简单处理为返回Double.MAX_VALUE，表示最大，放在排序列表的末尾
                                // 如果希望无效值放在开头，则返回Double.MIN_VALUE
                                return Double.MAX_VALUE;
                            }
                        }
                ))
                .collect(Collectors.toList());
        result.setOrderAgentPayDetailVos(sortedList);
        return result;
    }

    private String studioExpensesTotal(List<StudioExpenses> studioExpenses) {
        String total = "0";
        for (StudioExpenses studioExpense : studioExpenses) {
            total = PayCalculateUtils.add(total, studioExpense.getExpendValue()).toString();
        }
        return total;
    }

    private String getAgentTotal(List<OrderPayDetailVo> orderPayDetailInfos, Function<OrderPayDetailVo, String> valueGetter) {
        String total = "0";
        for (OrderPayDetailVo orderPayDetailInfo : orderPayDetailInfos) {
            if (valueGetter != null) {
                total = PayCalculateUtils.add(total, valueGetter.apply(orderPayDetailInfo)).toString();
            }
        }
        return total;
    }

    private String getTotal(List<OrderAgentPayDetailVo> orderPayDetailInfos, Function<OrderAgentPayDetailVo, String> predicate) {
        String total = "0";
        for (OrderAgentPayDetailVo orderPayDetailInfo : orderPayDetailInfos) {
            if (predicate != null) {
                total = PayCalculateUtils.add(total, predicate.apply(orderPayDetailInfo)).toString();
            }
        }
        return total;
    }

    private Map<String, String> getTotalMap(List<OrderPayDetailVo> agencyNameDetailList,
                                            Function<OrderPayDetailVo, String> groupFlag,
                                            Function<OrderPayDetailVo, String> valueGetter) {
        Map<String, String> totalMap = new HashMap<>();

        if (groupFlag == null || valueGetter == null) {
            return totalMap;
        }

        for (OrderPayDetailVo orderPayDetailInfo : agencyNameDetailList) {
            String key = groupFlag.apply(orderPayDetailInfo);
            String nowBusinessTotal = totalMap.get(key);
            if (nowBusinessTotal == null) {
                totalMap.put(key, valueGetter.apply(orderPayDetailInfo));
            } else {
                totalMap.put(key, PayCalculateUtils.add(nowBusinessTotal, valueGetter.apply(orderPayDetailInfo)).toString());
            }
        }
        return totalMap;
    }

    //各种业务的总利润计算
    private Map<String, String> getBusinessProfitMap(List<OrderPayDetailVo> agencyNameDetailList) {
        Map<String, String> totalIncomeMap = getTotalMap(agencyNameDetailList, OrderPayDetailVo::getBusinessType, OrderPayDetailVo::getPayValue);
        Map<String, String> totalExpenseMap = getTotalMap(agencyNameDetailList, OrderPayDetailVo::getBusinessType, OrderPayDetailVo::getRebateValue);
        Set<String> allTypes = new HashSet<>();
        Set<String> incomeTypes = totalIncomeMap.keySet();
        Set<String> expenseTypes = totalExpenseMap.keySet();
        allTypes.addAll(expenseTypes);
        allTypes.addAll(incomeTypes);
        Map<String, String> profitMap = new HashMap<>();
        for (String businessType : allTypes) {
            profitMap.put(businessType, PayCalculateUtils.sub(totalIncomeMap.getOrDefault(businessType, "0"), totalExpenseMap.getOrDefault(businessType, "0")).toString());
        }
        return profitMap;
    }

    //托管的新增或续费
    private Map<String, String> getTgTransactionTypeMap(List<OrderPayDetailVo> orderPayDetailInfos) {
        List<OrderPayDetailVo> tgDetails = orderPayDetailInfos.stream().filter(item -> StrUtil.equals("托管", item.getBusinessType())).collect(Collectors.toList());
        Map<String, String> incomeMap = getTotalMap(tgDetails, OrderPayDetailVo::getPayType, OrderPayDetailVo::getPayValue);
        Map<String, String> expenseMap = getTotalMap(tgDetails, OrderPayDetailVo::getPayType, OrderPayDetailVo::getRebateValue);
        Set<String> allKeys = new HashSet<>();
        allKeys.addAll(incomeMap.keySet());
        allKeys.addAll(expenseMap.keySet());
        Map<String, String> profitMap = new HashMap<>();
        for (String key : allKeys) {
            profitMap.put(key, PayCalculateUtils.sub(incomeMap.getOrDefault(key, "0"), expenseMap.getOrDefault(key, "0")).toString());
        }
        return profitMap;
    }

    //工作室支出方式
    private Map<String, String> getStudioExpensesMap(List<StudioExpenses> studioExpenses) {
        Map<String, String> totalMap = new HashMap<>();
        for (StudioExpenses studioExpense : studioExpenses) {
            String s = totalMap.get(studioExpense.getExpendWay());
            if (s == null) {
                totalMap.put(studioExpense.getExpendWay(), studioExpense.getExpendValue());
            } else {
                totalMap.put(studioExpense.getExpendWay(), PayCalculateUtils.add(s, studioExpense.getExpendValue()).toString());
            }
        }
        return totalMap;
    }

    private Map<String, String> getBalanceMap(List<OrderPayDetailVo> orderPayDetailInfos, List<StudioExpenses> studioExpenses) {
        Map<String, String> incomeWay = getTotalMap(orderPayDetailInfos, OrderPayDetailVo::getPayWay, OrderPayDetailVo::getPayValue);
        Map<String, String> rebateWay = getTotalMap(orderPayDetailInfos, OrderPayDetailVo::getRebateWay, OrderPayDetailVo::getRebateValue);
        Map<String, String> studioExpensesMap = getStudioExpensesMap(studioExpenses);
        Set<String> balanceMap = new HashSet<>();
        balanceMap.addAll(incomeWay.keySet());
        balanceMap.addAll(rebateWay.keySet());
        balanceMap.addAll(studioExpensesMap.keySet());
        for (String key : balanceMap) {
            BigDecimal keybalance = PayCalculateUtils.getBigDecimal(incomeWay.get(key)).subtract(PayCalculateUtils.getBigDecimal(rebateWay.get(key)));
            String result = PayCalculateUtils.sub(keybalance.toString(), studioExpensesMap.get(key));
            incomeWay.put(key, result);
        }
        return incomeWay;
    }

    private void totalMapHandle(OrderPayDetailStatisticsMainVo result, List<OrderPayDetailVo> orderPayDetailInfos, List<StudioExpenses> studioExpenses) {
        Map<String, String> businessIncomeTotalMap = getTotalMap(orderPayDetailInfos, OrderPayDetailVo::getPayWay, OrderPayDetailVo::getPayValue);
        result.setBusinessTotalIncomeMap(businessIncomeTotalMap);
        Map<String, String> businessRebateTotalMap = getTotalMap(orderPayDetailInfos, OrderPayDetailVo::getRebateWay, OrderPayDetailVo::getRebateValue);
        result.setBusinessTotalExpenditureMap(businessRebateTotalMap);
        Map<String, String> studioIncomeMap = getStudioExpensesMap(studioExpenses.stream()
                .filter(item -> Double.parseDouble(item.getExpendValue()) < 0)
                .map(item -> {
                    StudioExpenses studioExpenses1 = BeanUtil.copyProperties(item, StudioExpenses.class);
                    studioExpenses1.setExpendValue((PayCalculateUtils.sub("0", studioExpenses1.getExpendValue())));
                    return studioExpenses1;
                }).collect(Collectors.toList()));
        result.setStudioTotalIncomeMap(studioIncomeMap);
        Map<String, String> studioExpensesMap = getStudioExpensesMap(studioExpenses.stream().filter(item -> Double.parseDouble(item.getExpendValue()) > 0).collect(Collectors.toList()));
        result.setStudioTotalExpenditureMap(studioExpensesMap);
        Set<String> allKeys = new HashSet<>();
        allKeys.addAll(businessIncomeTotalMap.keySet());
        allKeys.addAll(businessRebateTotalMap.keySet());
        allKeys.addAll(studioIncomeMap.keySet());
        allKeys.addAll(studioExpensesMap.keySet());
        Map<String, String> totalIncomeMap = new HashMap<>();
        Map<String, String> totalRebateMap = new HashMap<>();
        Map<String, String> totalProfitMap = new HashMap<>();
        String totalIncome = "0";
        String totalRebate = "0";
        for (String key : allKeys) {
            totalIncomeMap.put(key, PayCalculateUtils.add(totalIncomeMap.getOrDefault(key, "0"), businessIncomeTotalMap.getOrDefault(key, "0")).toString());
            totalIncomeMap.put(key, PayCalculateUtils.add(totalIncomeMap.getOrDefault(key, "0"), studioIncomeMap.getOrDefault(key, "0")).toString());
            totalRebateMap.put(key, PayCalculateUtils.add(totalRebateMap.getOrDefault(key, "0"), businessRebateTotalMap.getOrDefault(key, "0")).toString());
            totalRebateMap.put(key, PayCalculateUtils.add(totalRebateMap.getOrDefault(key, "0"), studioExpensesMap.getOrDefault(key, "0")).toString());
            //总收入
            totalIncome = PayCalculateUtils.add(totalIncome, businessIncomeTotalMap.getOrDefault(key, "0")).toString();
            totalIncome = PayCalculateUtils.add(totalIncome, studioIncomeMap.getOrDefault(key, "0")).toString();
            //总支出
            totalRebate = PayCalculateUtils.add(totalRebate, businessRebateTotalMap.getOrDefault(key, "0")).toString();
            totalRebate = PayCalculateUtils.add(totalRebate, studioExpensesMap.getOrDefault(key, "0")).toString();
            //总利润
            totalProfitMap.put(key, PayCalculateUtils.sub(totalIncomeMap.getOrDefault(key, "0"), totalRebateMap.getOrDefault(key, "0")));
        }
        result.setTotalIncome(totalIncome);
        result.setTotalExpenditure(totalRebate);
        result.setTotalProfit(PayCalculateUtils.sub(totalIncome, totalRebate));
        result.setTotalIncomeMap(totalIncomeMap);
        result.setTotalExpenditureMap(totalRebateMap);
        result.setWalletBalance(totalProfitMap);

        //业务相关统计参数
        result.setTotalBusinessIncome(getTotalFromMap(businessIncomeTotalMap));
        result.setTotalBusinessExpenditure(getTotalFromMap(businessRebateTotalMap));
        result.setTotalBusinessProfit(PayCalculateUtils.sub(result.getTotalBusinessIncome(), result.getTotalBusinessExpenditure()));
        result.setBusinessTotalIncomeMap(businessIncomeTotalMap);
        result.setBusinessTotalExpenditureMap(businessRebateTotalMap);
        Set<String> businessIncomeKeys = businessIncomeTotalMap.keySet();
        Set<String> businessRebateKeys = businessRebateTotalMap.keySet();
        Set<String> businessKeys = new HashSet<>();
        businessKeys.addAll(businessIncomeKeys);
        businessKeys.addAll(businessRebateKeys);
        Map<String, String> businessWalletBalance = new HashMap<>();
        for (String key : businessKeys) {
            String income = businessIncomeTotalMap.getOrDefault(key, "0");
            String expend = businessRebateTotalMap.getOrDefault(key, "0");
            businessWalletBalance.put(key, PayCalculateUtils.sub(income, expend));
        }
        result.setBusinessWalletBalance(businessWalletBalance);
        //工作室相关统计参数
        result.setTotalStudioIncome(getTotalFromMap(studioIncomeMap));
        result.setTotalStudioExpenditure(getTotalFromMap(studioExpensesMap));
        result.setTotalStudioProfit(PayCalculateUtils.sub(result.getTotalStudioIncome(), result.getTotalStudioExpenditure()));
        result.setStudioTotalIncomeMap(studioIncomeMap);
        result.setStudioTotalExpenditureMap(studioExpensesMap);
        Set<String> studioIncomeKeys = studioIncomeMap.keySet();
        Set<String> studioRebateKeys = studioExpensesMap.keySet();
        Set<String> studioKeys = new HashSet<>();
        studioKeys.addAll(studioIncomeKeys);
        studioKeys.addAll(studioRebateKeys);
        Map<String, String> studioWalletBalance = new HashMap<>();
        for (String key : studioKeys) {
            String income = studioIncomeMap.getOrDefault(key, "0");
            String expend = studioExpensesMap.getOrDefault(key, "0");
            studioWalletBalance.put(key, PayCalculateUtils.sub(income, expend));
        }
        result.setStudioWalletBalance(studioWalletBalance);
    }

    private String getTotalFromMap(Map<String, String> map) {
        String total = "0";
        Collection<String> values = map.values();
        for (String value : values) {
            total = PayCalculateUtils.add(total, value).toString();
        }
        return total;
    }

    public Page<OrderMainForTrusteeshipVo> getAnswerStatics(Page<OrderMainForTrusteeshipVo> page, AnswerStatisticQuery query) {
        return this.statisticsMapper.getAnswerStatics(page, query);
    }

    public List<OrderPayAgentDetailVo> getAgentPayDetail(PayDetailStatisticsQuery query) {
        return this.statisticsMapper.getAgentPayDetail(query);
    }


}
